#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>

#include "fetion_libc.h"

// #define	LoginUri	"/huc/user/space/login.do?m=submit&fr=space"
// #define	LoginSkipUri	"/im/login/cklogin.action"
// #define	HOST	"f.10086.cn"
// #define	PORT	80
// #define	COMTENTTYPE "Content-Type: application/x-www-form-urlencoded\r\n" 
// #define	USERAGENT "User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20100101 Firefox/14.0.1\r\n" 
// #define	CONNECTION	"Connection: close\r\n\r\n"

static int SendMyself(const char *msg);
static int SendFriend(const char *uid, const char *msg);
static char* GetUid(const char *mobilenum);
static char* GetCsrfToken(const char *uid);
static char *PostWeb(const char *uri, const char *data, char *rcvdata);
static char *ParseStr(char *str, const char *hdelimiter,const char *tdelimiter);

static char Cookie[BUFSIZ] = "";
static char g_Uid[20] = "";
static char g_CsrfToken[128] = "";
static char g_Username[15] = "";

/*
*	fountction	:	登录
*	param1	in	:	用户名
*	param2	in	:	密码
*	return   	:  	登录失败	 EPWD/EMOD
*					登录成功	TRUE
*/
int Login(const char *user, const char *password)
{
	char LoginData[128];
	char buffer[BUFSIZ];	
	char *retp = NULL;
	char *delimtp = NULL;
	
	sprintf(LoginData, "mobilenum=%s&password=%s", user, password);
	retp= PostWeb("/huc/user/space/login.do?m=submit&fr=space", LoginData, buffer);
	
#ifdef DEBUG
	// 打印登录界面的数据
	printf(" \nLogin PostWeb  return data : \n%s \n", retp);
#endif
	
	if(memcmp("HTTP/1.1 302 Moved Temporarily", retp, 30) != 0)
	{
		// printf("login failure : Please confirm the account or password again !\n");
	return EPWD;
	}
	// Parse Cookies
	delimtp = retp;
	while((retp = ParseStr(delimtp, "Set-Cookie:", ";")) != NULL)
	{
		delimtp = NULL;
		strcat(Cookie, retp);
		strcat(Cookie, ";");
	}
	Cookie[strlen(Cookie) - 1] = '\0';	
	
#ifdef DEBUG
	// 打印解析得到的 Cookie
	printf("Cookie data:\n%s\n", Cookie);
#endif
	
	//PostWeb("/im/login/cklogin.action", NULL, NULL);
	retp = PostWeb("/im/login/cklogin.action", NULL, buffer);
	
#ifdef DEBUG
	// 打印 skip 界面的数据
	printf("\nLogin skip PostWeb  return data :\n%s\n", retp);
#endif	

	if(memcmp("HTTP/1.1 200 OK", retp, 15) != 0)
	{
		// printf("login skip failure : Maybe Account at protection mode\n");
	return EMOD;
	}
	strcpy(g_Username, user);
return TRUE;
}

/*
*	fountction	:	注销
*	return	:	 FALSE/TRUE
*/
int	Logout()
{
	char buffer[BUFSIZ];
	char *retp;
	
	retp= PostWeb("/im/index/logoutsubmit.action", NULL, buffer);	
#ifdef DEBUG
	// 打印 Logout 界面的数据
	printf("\nLogout PostWeb  return data :\n%s\n", retp);
#endif	

	if(memcmp("HTTP/1.1 200 OK", retp, 15) != 0)
	{
	return FALSE;
	}
	//printf("logout successfully .\n");
return TRUE;
}

/**
 * 	给自己发飞信
 *	param  (in):  message
 *	return:		FALSE/TRUE
 */
static int SendMyself(const char *msg)
{
	char sendmsg[180] = "msg=";
	char buffer[BUFSIZ] = "";
	char *retp = NULL;
	
	strcat(sendmsg, msg);
	retp = PostWeb("/im/user/sendMsgToMyselfs.action", sendmsg, buffer);
#ifdef DEBUG
	// 给自己发信息的返回数据
	printf("Send massage to myself return data:\n%s\n", retp);
#endif	
	
	if(memcmp("HTTP/1.1 200 OK", retp, 15) != 0)
	{
	return FALSE;
	}	
	// if(strstr(retp, "短信发送成功!") == NULL)
		// return FALSE;
return TRUE;
}

/*
*	fountction	:	向好友发信息
*	param1	(in):	好友飞信ID
*	param2	(in):	信息内容
*	return  :  		 
*						
*/
static int SendFriend(const char *uid, const char *msg)
{
	char sendDat[BUFSIZ] = "msg=";
	char friendUri[64] = "/im/chat/sendMsg.action?touserid=";  //好友UID有多长 ?   8 ~10
	char buffer[BUFSIZ] = "";
	char *retp;
	char *csrfToken;
	
	strcat(friendUri, uid);
	
	csrfToken = GetCsrfToken(uid);
	strcat(sendDat, msg);
	strcat(sendDat, "&csrfToken=");
	strcat(sendDat, csrfToken);
	
	retp = PostWeb(friendUri, sendDat,buffer);
#ifdef DEBUG
		// 向好友发信息的返回数据
	printf("Send massage to friend return data:\n%s\n", retp);
#endif	

/*
	if(memcmp("HTTP/1.1 200 OK", retp, 15) != 0)
	{
	return FALSE;
	}	
*/
return TRUE;
}

/*
*	fountction	:	发信息通用接口
*	param1	(in):	手机号(接收者)
*	param2	(in):	信息内容
*	return   :	FALSE/TRUE  		 
*						
*/
int SendMsg(const char *rcvmobile, const char *msg)
{

	char *uid = NULL;
	int ret;
		
	if (*msg == 0)
	{
		return EMSGEMPTY;
	}
   //判断是给自己发还是给好友发
	if (strcmp(rcvmobile, g_Username) != 0)
	{		
		if((uid = GetUid(rcvmobile)) == NULL)
			return FALSE;	
		ret = SendFriend(uid, msg);
		if(ret == FALSE)
		{
			return FALSE;
		}
#ifdef DEBUG
		// 发送给好友成功
	printf("Send massage to friend successed ..\n");
#endif	
	}
	else
	{
		ret = SendMyself(msg);
		if(ret == FALSE)
		{
			return FALSE;
		}
#ifdef DEBUG
		// 发送给自己成功
	printf("Send massage to myself successed ..\n");
#endif	
			
	}
return TRUE;

}

/**    
*	Fountction:	获取csrfToken (用于给好友发信息)
* 	param1	(in):	飞信ID  
*	return:	FALSE/TRUE     
*/
static char* GetCsrfToken(const char *uid)
{
	char csrfTokenUri[128] = "/im/chat/toinputMsg.action?touserid=";
	char buffer[BUFSIZ] = "";
	char *retp;
	char *head = NULL, *trail = NULL;

	strcat(csrfTokenUri, uid);
	retp = PostWeb(csrfTokenUri, NULL,buffer);
#ifdef DEBUG
		// 获取csrfToken 返回的数据
	printf("Get  csrfToken return data:\n%s\n", retp);
#endif	

	// Parse csrfToken
	head = strstr(retp, "csrfToken");
	head += (strlen("csrfToken") + 9); 
	memcpy(g_CsrfToken, head, 32);
	retp = g_CsrfToken;


#ifdef DEBUG	
	printf("\nCsrfToken:%s\n", retp);
#endif	

return retp;
}

/*
*	fountction	:	获取飞信ID
*	param1	(in):	手机号
*	return	:  		成功返回 Uid 字串，失败返回NULL
*	Description: 每个帐号的 ID 是固定的.					
*/
static char* GetUid(const char *mobilenum)
{
	char buffer[BUFSIZ];
	char uidData[32];
	char *retp = NULL;
	char *head = NULL, *trail = NULL;
	
	sprintf(uidData, "searchText=%s", mobilenum);
	retp = PostWeb("/im/index/searchOtherInfoList.action", uidData, buffer);
#ifdef DEBUG
	// 获取  Uid 时返回的数据
	printf("\nGetUid return data:\n%s\n", retp);
#endif		
	// Parse Uid
	if((retp = ParseStr(retp, "touserid=", "&")) == NULL)
	{
	return NULL;
	}
	strcpy(g_Uid, retp);
	retp = g_Uid;
#ifdef DEBUG
printf("\n uid: %s\n", retp);
#endif
return retp;

}

/*
*	fountction	:	携带 Cookie 向服务器提交数据
*	param1	(in):	web_url
*	param2	(in):	send web data
*	param3	(out): 	received data buffer
*	return	:	point to recived data 
				when param3 is NULL ，return NULL
*	Description:	注意，buffer设置为 null 时不能接受到服务器发回的数据,函数将返回一个空地址
*/
static char *PostWeb(const char *uri, const char *data, char *buffer)
{
	int sockfd;
	struct hostent *remoteHost = NULL;
	struct sockaddr_in addr;
	char header[BUFSIZ] = "";
	char header_Cookie[BUFSIZ] = "";
	char header_datalen[64] = "";	
	char *retp = NULL;
	char webData[BUFSIZ];


	//  检测网络连通性
	if((remoteHost = gethostbyname("f.10086.cn")) == NULL)
	{
		printf("Error resolving host . Please check your internet connection !\n");
		exit(1);
	}
	
	//	配置连接socket所需参数
	bzero(&addr, sizeof(addr)); 
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = *((unsigned long*)remoteHost->h_addr);
	addr.sin_port = htons(80);
	
	// 创建 socket 
	if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 )
	{
		printf("Error opening socket ! \n");
		exit(1);
	}

	// 配置 发送的 web  数据
	memset(header, 0, BUFSIZ);
	sprintf(header, "POST %s HTTP/1.1\r\n", uri);
	strcat(header, "Host: f.10086.cn\r\n");
	sprintf(header_Cookie, "Cookie:%s\r\n", Cookie);
	strcat(header, header_Cookie);
	strcat(header, "Content-Type: application/x-www-form-urlencoded\r\n");
	strcat(header, "User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:14.0) Gecko/20100101 Firefox/14.0.1\r\n");

	if (data == NULL) // stract() 函数不能连接空字符，所以需要此判断语句
	{
		strcat(header, "Content-Length: 0\r\n");
		strcat(header, "Connection: close\r\n\r\n");
		
	}
	else
	{
		sprintf(header_datalen, "Content-Length: %d\r\n", strlen(data));
		strcat(header, header_datalen); 		//strcat(header, "Content-Length: ".strlen($data)."\r\n");	
		strcat(header, "Connection: close\r\n\r\n");
		strcat(header, data);
	}

#ifdef DEBUG
	// 打印提交给服务器的 header 数据
printf("\ndata post to webservice data: \n %s\n", header);
#endif

	//	连接服务器，并发送请求 header
	connect(sockfd,(struct sockaddr *)&addr,sizeof(struct sockaddr_in));
	send(sockfd, header, strlen(header), 0);
	
	// 接收数据	
	if(buffer != NULL)	//   注意，buffer设置为 null 时不能接受到服务器发回的数据。
	{
		memset(buffer, 0, strlen(buffer));	
		
#if 1	// 待改进	
		recv(sockfd, buffer, BUFSIZ, 0);	//  接收两次
		recv(sockfd, webData, BUFSIZ, 0);
		if(*webData !=  '\0')
			strcat(buffer,webData);
#else  	
		if(recv(sockfd, webData, BUFSIZ, 0) != 0)	// 经验证每次接受的数据大小为1380(为了防止接收的数据不够用还是都接受了吧)
		{
			if(*webData != 0)
				strcat(buffer,webData);
			memset(webData, 0, strlen(webData));	
		}		  
#endif 				
		retp = buffer;
	}
	
	close(sockfd);	// 关闭本次连接
return retp;
}

/*
*	fountction:	分割字符串
*	param:
*		str		分割对象		in
*		delim1	header分割符	in
*	   	delim2	trail分割符	in
*	return:	指向分割结果
*			NULL	代表str中分割不出
*	Notice:	参数 str所指向的内容不能为常量(函数内部会修改其指向的内容)
*/
static char *ParseStr(char *str, const char *hdelimiter,const char *tdelimiter)
{
	char *head;
	char *trail = NULL;
	int len;
	static char *s_oldpst = NULL;
	
	head = str;
	if(head == NULL)
		head = s_oldpst;
		
	if((head = strstr(head, hdelimiter)) == NULL)
	{		
	return NULL;
	}		
	head += strlen(hdelimiter);
	if((trail = strstr(head,tdelimiter)) == NULL)
	{
	return NULL;
	}
	*trail = '\0';
	trail++;
	s_oldpst = trail;
return head;
}


